/*
 * Main.c
 *
 *  Created on  : 13 April 2021
 *  Modified on : 3 May 2021
 *  Author      : HWanyusof
 *  Version     : 1.0
 */

#include "usbd_cdc_if.h"
#include "string.h"
#include "stm32f4xx_hal.h"
#include "VCNL36825T.h"
#include "VCNL36825T_Prototypes.h"
#include "typedefinition.h"
#include "VCNL36825T_Application_Library.h"
#include "Main_User.h"


//Global Variables
int SEL_PS_Mode;
int SEL_Print_Mode;
int SEL_Offset;

//Switch the I2C Bus number here
int I2C_Bus = 2;

//Variables for Offset Value
int CalibValue = 0;
int OffsetValue = 0;
int AverageCount = 10; //Change the average count to the needed number of offset measurement

/* Function Prototypes */
void AF_Mode();
void Auto_Mode();
void Low_Power_Mode();
void Auto_Calibration_Mode();

void INIT_VCNL36825T()
{

    /* Reset Sensor to default value */
	Reset_Sensor();

	/****************************************************************************/
	/***********************Setting Up The Mode & Variables**********************/

	/* Choose a desired proximity mode */
	/*
	 * SEL_PS_Mode - Select the proximity mode:
	 * 0 - Turn Off proximity mode/shutdown
	 * 1 - Auto/Self-Timed Mode
	 * 2 - Active Force Mode/Continuous Forced Mode
	 * 3 - Low Power Mode
	 * 4 - Auto Calibration Mode
	 *
	 */
	SEL_PS_Mode = 1;

	/* Choose the print mode */
	/*
	 * SEL_Print_Mode - Select the print mode:
	 * 1 - Print individual mode output data (PS data)
	 * 2 - Print all of the register values (Including PS output data registers)
	 * 3 - Print all of the sensor register settings
	 *
	 */
	SEL_Print_Mode = 2;

	/* Choose to turn on/off offset cancellation measurement */
    //Only applicable for  Auto, AF and Low Power Mode
    //Auto Calibration will perform the offset measurement automatically based on the selected settings
	/* SEL_Offset - Select the offset mode:
	 * 0 - Turn Off offset cancellation measurement
	 * 1 - Turn On offset cancellation measurement
	 */
	SEL_Offset = 0;

	/*******************End of Setting Up The Mode & Variables*******************/
	/****************************************************************************/

	/****************************************************************************/
	/**********************Implementation of above settings**********************/

	/* Set the proximity mode */
	switch(SEL_PS_Mode)
	{
		case 1  : Auto_Mode(); //Also known as Self-Timed Mode
				  break;
		case 2  : AF_Mode(); //Also known Continuous Forced Mode (Could also be used for single forced mode)
		          break;
		case 3  : Low_Power_Mode(); //Auto/Self-Timed Mode with measurement period defined by PS_LPPER
				  break;
        case 4  : Auto_Calibration_Mode(); //Continuous Forced Mode with Automatic Calibration (Automatic Offset Cancellation)
				  break;
		default : break;
	}

	/***************************End of Implementation****************************/
    /****************************************************************************/
}

//Print Function
void PRINT_VCNL36825T()
{
	/* Print the output based on the mode */
	switch(SEL_Print_Mode)
	{
		case 1 : 	switch(SEL_PS_Mode)
					{
						case 1  : Print_Auto_Mode();
								  break;
						case 2  : Print_AF_Mode();
								  break;
						case 3  : Print_Low_Power_Mode();
								  break;
						case 4  : Print_Auto_Calibration_Mode();
								  break;
						default : break;
					}
					break;

		case 2 :	Print_All();
					break;

		case 3 :	Print_Register_Settings();
					break;

		default :   break;
	}

	/* Place your application code here. */

}

void Low_Power_Mode()
{
	//1.)Initialization
    //Switch On the sensor
	VCNL36825T_SET_PS_ON(VCNL36825T_PS_ON_EN);
	VCNL36825T_SET_PS_CAL(VCNL36825T_PS_CAL_EN);
    //Ensure that PS_ST = 1 before setting up PS_AF = Auto
    VCNL36825T_SET_PS_ST(VCNL36825T_PS_ST_STOP);
	//Setting up Auto Mode
	VCNL36825T_SET_PS_AF(VCNL36825T_PS_AUTO);

	//2.) Setting up PS
	//PS_CONF1_L and PS_CONF1_H
	//have been set up during the initialization

	//PS_CONF2_L
	//Set the sample Period of measurement (When PS_LPEN = 1 / Low Power Mode Enabled, then the bit PS_PERIOD is ignored)
	//Set the Persistence
	VCNL36825T_SET_PS_PERS(VCNL36825T_PS_PERS_1);
	//Set the Interrupt Mode
	VCNL36825T_SET_PS_INT(VCNL36825T_PS_INT_EN);
	//Enable/Disable Smart Persistence
	VCNL36825T_SET_PS_SMART_PERS(VCNL36825T_PS_SMART_PERS_DIS);
	//PS_ST will be set when starting the measurement

	//PS_CONF2_H
	//Set the Integration Time
	VCNL36825T_SET_PS_IT(VCNL36825T_PS_IT_1T);
	//Set the MPS
	VCNL36825T_SET_PS_MPS(VCNL36825T_PS_MPS_1);
	//Set the IT Bank
	VCNL36825T_SET_PS_ITB(VCNL36825T_PS_ITB_50);
	//Enable/Disable the High Gain setting
	VCNL36825T_SET_PS_HG(VCNL36825T_PS_HG_DIS);

	//PS_CONF3_L
	//Set the PS sunlight protect
	VCNL36825T_SET_PS_SP_INT(VCNL36825T_PS_SP_INT_EN);
	//Set number of detect cycle after trigger
	VCNL36825T_SET_PS_FORCENUM(VCNL36825T_PS_FORCENUM_1);
	//PS_AF = Auto has been set during initialization

	//PS_CONF3_H
	//Set the sunlight cancellation
	VCNL36825T_SET_PS_SC(VCNL36825T_PS_SC_EN);
	//Set the Sensor output Bit Size
	VCNL36825T_SET_PS_HD(VCNL36825T_PS_HD_12Bits);
	//Set the VCSEL current
	VCNL36825T_SET_I_VCSEL(VCNL36825T_I_VCSEL_10mA);

    //PS_CONF4_H
    //Enable Low Power Mode
    VCNL36825T_SET_PS_LPEN(VCNL36825T_PS_LPEN_EN);
    //Set the detection Period for Low Power Mode
    VCNL36825T_SET_PS_LPPER(VCNL36825T_PS_LPPER_320ms);

    //3.) Starting the PS
	VCNL36825T_SET_PS_ST(VCNL36825T_PS_ST_START);

    //4.) Threshold Setting and Offset Measurement
	for(int i=0;i<AverageCount;i++)
	{
		//Delay of 10 ms needs to be changed depending on the API of the µ-controller of use
		HAL_Delay(10);
		CalibValue += VCNL36825T_GET_PS_DATA();
		//Delay of 10 ms needs to be changed depending on the API of the µ-controller of use
		HAL_Delay(10);
	}

	//Calculate the average of the offset measurement
	CalibValue /= AverageCount;

	//Perform Offset Measurement
	if(SEL_Offset == 0) OffsetValue = 0;
	if(SEL_Offset == 1) OffsetValue = CalibValue;
	//Set Cancellation register to eliminate offset
	VCNL36825T_SET_PS_CANC(OffsetValue);
	//Set Low Threshold
	VCNL36825T_SET_PS_LowThreshold(1000);
	//Set High Threshold
	VCNL36825T_SET_PS_HighThreshold(1500);

    //Delay of 10 ms needs to be changed depending on the API of the µ-controller of use
    HAL_Delay(10);
    //Clear initial interrupt
    VCNL36825T_GET_PS_INT_FLAG();

	HAL_Delay(1000);
}

void AF_Mode()
{
	//1.)Initialization
    //Switch On the sensor
	VCNL36825T_SET_PS_ON(VCNL36825T_PS_ON_EN);
	VCNL36825T_SET_PS_CAL(VCNL36825T_PS_CAL_EN);
    //Ensure that PS_ST = 1 before setting up PS_AF
    VCNL36825T_SET_PS_ST(VCNL36825T_PS_ST_STOP);
	//Setting up AF Mode
	VCNL36825T_SET_PS_AF(VCNL36825T_PS_AF_EN);

	//2.) Setting up PS
	//PS_CONF1_L and PS_CONF1_H
	//have been set up during the initialization

	//PS_CONF2_L
	//PS_PRIOD doesn't have to be set for AF Mode
	//Set the Persistence
	VCNL36825T_SET_PS_PERS(VCNL36825T_PS_PERS_1);
	//Set the Interrupt Mode
	VCNL36825T_SET_PS_INT(VCNL36825T_PS_INT_EN);
	//Enable/Disable Smart Persistence
	VCNL36825T_SET_PS_SMART_PERS(VCNL36825T_PS_SMART_PERS_DIS);
	//PS_ST will be set when starting the measurement

	//PS_CONF2_H
	//Set the Integration Time
	VCNL36825T_SET_PS_IT(VCNL36825T_PS_IT_8T);
	//Set the MPS
	VCNL36825T_SET_PS_MPS(VCNL36825T_PS_MPS_1);
	//Set the IT Bank
	VCNL36825T_SET_PS_ITB(VCNL36825T_PS_ITB_50);
	//Enable/Disable the High Gain setting
	VCNL36825T_SET_PS_HG(VCNL36825T_PS_HG_DIS);

	//PS_CONF3_L
	//Set the PS sunlight protect
	VCNL36825T_SET_PS_SP_INT(VCNL36825T_PS_SP_INT_EN);
	//Set number of detect cycle after trigger
	VCNL36825T_SET_PS_FORCENUM(VCNL36825T_PS_FORCENUM_1);
	//PS_AF has been set during initialization and PS_TRIG needs to be set before doing proximity measurement

	//PS_CONF3_H
	//Set the sunlight cancellation
	VCNL36825T_SET_PS_SC(VCNL36825T_PS_SC_EN);
	//Set the Sensor output Bit Size
	VCNL36825T_SET_PS_HD(VCNL36825T_PS_HD_12Bits);
	//Set the VCSEL current
	VCNL36825T_SET_I_VCSEL(VCNL36825T_I_VCSEL_20mA);

    //PS_CONF4_H
    //Disable Low Power Mode
    VCNL36825T_SET_PS_LPEN(VCNL36825T_PS_LPEN_DIS);

    //3.) Starting the PS
	VCNL36825T_SET_PS_ST(VCNL36825T_PS_ST_START);

    //4.) Threshold Setting and Offset Measurement
	for(int i=0;i<AverageCount;i++)
	{
		//Enable trigger to start offset measurement
		VCNL36825T_SET_PS_TRIG(VCNL36825T_PS_TRIG_EN);
		//Delay of 10 ms needs to be changed depending on the API of the µ-controller of use
		HAL_Delay(10);
		CalibValue += VCNL36825T_GET_PS_DATA();
		//Delay of 10 ms needs to be changed depending on the API of the µ-controller of use
		HAL_Delay(10);
	}

	//Calculate the average of the offset measurement
	CalibValue /= AverageCount;

	//Perform Offset Measurement
	if(SEL_Offset == 0) OffsetValue = 0;
	if(SEL_Offset == 1) OffsetValue = CalibValue;
	//Set Cancellation register to eliminate offset
	VCNL36825T_SET_PS_CANC(OffsetValue);
	//Set Low Threshold
	VCNL36825T_SET_PS_LowThreshold(1000);
	//Set High Threshold
	VCNL36825T_SET_PS_HighThreshold(1500);

    //Delay of 10 ms needs to be changed depending on the API of the µ-controller of use
    HAL_Delay(10);
    //Clear initial interrupt
    VCNL36825T_GET_PS_INT_FLAG();

	HAL_Delay(1000);
}

void Auto_Mode()
{
	//1.)Initialization
    //Switch On the sensor
	VCNL36825T_SET_PS_ON(VCNL36825T_PS_ON_EN);
	VCNL36825T_SET_PS_CAL(VCNL36825T_PS_CAL_EN);
    //Ensure that PS_ST = 1 before setting up PS_AF = Auto
    VCNL36825T_SET_PS_ST(VCNL36825T_PS_ST_STOP);
	//Setting up Auto Mode
	VCNL36825T_SET_PS_AF(VCNL36825T_PS_AUTO);

	//2.) Setting up PS
	//PS_CONF1_L and PS_CONF1_H
	//have been set up during the initialization

	//PS_CONF2_L
	//Set the sample Period of measurement
	VCNL36825T_SET_PS_PERIOD(VCNL36825T_PS_PERIOD_10ms);
	//Set the Persistence
	VCNL36825T_SET_PS_PERS(VCNL36825T_PS_PERS_1);
	//Set the Interrupt Mode
	VCNL36825T_SET_PS_INT(VCNL36825T_PS_INT_EN);
	//Enable/Disable Smart Persistence
	VCNL36825T_SET_PS_SMART_PERS(VCNL36825T_PS_SMART_PERS_DIS);
	//PS_ST will be set when starting the measurement

	//PS_CONF2_H
	//Set the Integration Time
	VCNL36825T_SET_PS_IT(VCNL36825T_PS_IT_8T);
	//Set the MPS
	VCNL36825T_SET_PS_MPS(VCNL36825T_PS_MPS_1);
	//Set the IT Bank
	VCNL36825T_SET_PS_ITB(VCNL36825T_PS_ITB_50);
	//Enable/Disable the High Gain setting
	VCNL36825T_SET_PS_HG(VCNL36825T_PS_HG_DIS);

	//PS_CONF3_L
	//Set the PS sunlight protect
	VCNL36825T_SET_PS_SP_INT(VCNL36825T_PS_SP_INT_EN);
	//Set number of detect cycle after trigger
	VCNL36825T_SET_PS_FORCENUM(VCNL36825T_PS_FORCENUM_1);
	//PS_AF has been set during initialization and PS_TRIG needs to be set before doing proximity measurement

	//PS_CONF3_H
	//Set the sunlight cancellation
	VCNL36825T_SET_PS_SC(VCNL36825T_PS_SC_EN);
	//Set the Sensor output Bit Size
	VCNL36825T_SET_PS_HD(VCNL36825T_PS_HD_12Bits);
	//Set the VCSEL current
	VCNL36825T_SET_I_VCSEL(VCNL36825T_I_VCSEL_10mA);

    //PS_CONF4_H
    //Disable Low Power Mode
    VCNL36825T_SET_PS_LPEN(VCNL36825T_PS_LPEN_DIS);

    //3). Starting the PS
	VCNL36825T_SET_PS_ST(VCNL36825T_PS_ST_START);

    //4.) Threshold Setting and Offset Measurement
	for(int i=0;i<AverageCount;i++)
	{
		//Delay of 10 ms needs to be changed depending on the API of the µ-controller of use
		HAL_Delay(10);
		CalibValue += VCNL36825T_GET_PS_DATA();
		//Delay of 10 ms needs to be changed depending on the API of the µ-controller of use
		HAL_Delay(10);
	}

	//Calculate the average of the offset measurement
	CalibValue /= AverageCount;

	//Perform Offset Measurement
	if(SEL_Offset == 0) OffsetValue = 0;
	if(SEL_Offset == 1) OffsetValue = CalibValue;
	//Set Cancellation register to eliminate offset
	VCNL36825T_SET_PS_CANC(OffsetValue);
	//Set Low Threshold
	VCNL36825T_SET_PS_LowThreshold(1000);
	//Set High Threshold
	VCNL36825T_SET_PS_HighThreshold(1500);

    //Delay of 10 ms needs to be changed depending on the API of the µ-controller of use
    HAL_Delay(10);
    //Clear initial interrupt
    VCNL36825T_GET_PS_INT_FLAG();

	HAL_Delay(1000);
}

void Auto_Calibration_Mode()
{
    //1.) Turn off the sensor
    //PS_CONF1_L
	VCNL36825T_SET_PS_ON(VCNL36825T_PS_ON_DIS);
	VCNL36825T_SET_PS_CAL(VCNL36825T_PS_CAL_DIS);
    //PS_CONF2_L
    VCNL36825T_SET_PS_ST(VCNL36825T_PS_ST_STOP);

    //2.) Set the Sensor Parameter
    //PS_CONF2_L
    //Set the Interrupt Mode
	VCNL36825T_SET_PS_INT(VCNL36825T_PS_INT_EN);

    //PS_CONF2_H
    //Set the Integration Time
    VCNL36825T_SET_PS_IT(VCNL36825T_PS_IT_8T);
    //Set the IT Bank
    VCNL36825T_SET_PS_ITB(VCNL36825T_PS_ITB_50);

    //PS_CONF3_L
    //Setting up AF Mode
    VCNL36825T_SET_PS_AF(VCNL36825T_PS_AF_EN);

    //PS_CONF3_H
    //Set the sunlight cancellation
    VCNL36825T_SET_PS_SC(VCNL36825T_PS_SC_EN);
    //Set the LED current
    VCNL36825T_SET_I_VCSEL(VCNL36825T_I_VCSEL_20mA);

    //3.) Set the Auto Calibration parameters
    //PS_CONF4_L
    //Set the PS_AC parameters
    VCNL36825T_SET_PS_AC(VCNL36825T_PS_AC_EN);
    VCNL36825T_SET_PS_AC_PERIOD(VCNL36825T_PS_AC_PERIOD_3ms);
    VCNL36825T_SET_PS_AC_NUM(VCNL36825T_PS_AC_NUM8);
    VCNL36825T_SET_PS_AC_TRIG(VCNL36825T_PS_AC_TRIG_DIS);
    VCNL36825T_SET_PS_AC_INT(VCNL36825T_PS_AC_INT_EN);

    //4.) Switch on the sensor
    //Switch the sensor on
    //PS_CONF1_L
	VCNL36825T_SET_PS_ON(VCNL36825T_PS_ON_EN);
	VCNL36825T_SET_PS_CAL(VCNL36825T_PS_CAL_EN);
    //PS_CONF2_L
    VCNL36825T_SET_PS_ST(VCNL36825T_PS_ST_START);

    //5.) Trigger the Auto Calibration Measurement
    VCNL36825T_SET_PS_AC_TRIG(VCNL36825T_PS_AC_TRIG_EN);

    //6.) Delay for Auto Calibration measurement
    //This delay depends on the AC_Period and Auto Calibration Number of Measurement
    //For Example PS_AC_PERIOD = 3ms and PS_AC_NUM = 8 -> (3ms * 8) + tolorance ≈ 30ms
    HAL_Delay(VCNL36825T_GET_DELAY_PS_AC());

    //7.) Read Interrupt for Auto Calibration measurement
    Print_PS_AC_INT_STATUS();

    //8.) Threshold Setting
    //Set Low Threshold
	VCNL36825T_SET_PS_LowThreshold(1000);
	//Set High Threshold
	VCNL36825T_SET_PS_HighThreshold(1500);

	HAL_Delay(1000);
}

/* [] END OF FILE */
